﻿#include "study10.h"
// C/C++ 标准库学习网站：https://legacy.cplusplus.com
// C/C++ 微软(Visual Studio)中文学习网站：https://learn.microsoft.com/zh-cn/cpp/cpp/?view=msvc-170

using namespace std; // 命名空间声明

static string read_file_as_string(const string& filename, bool& success) {
    // 老旧语法增加一个引用 bool 变量 success，用于指示是否成功读取文件
    ifstream file(filename); // 打开文件，失败返回空值，成功返回 ifstream 对象变量 file
    if (file) {
        string content((istreambuf_iterator<char>(file)), istreambuf_iterator<char>());// 读取文件内容
        // istreambuf_iterator 这里用来迭代 char 类型数据，ifstream 类型数据可以迭代 char 类型数据
        file.close(); // 关闭文件
        success = true; // 成功读取文件
        return content; // 返回文件内容
    }
    success = false; // 失败读取文件
    return ""; // 返回空字符串
}

static optional<string> read_file_as_optional(const string& filename) {
    // 新版本文件读取函数，返回一个 optional 类型变量，可包含文件内容或者空值
    ifstream file(filename); // 打开文件，失败返回空值，成功返回 ifstream 对象变量 file
    if (file) {
        string content((istreambuf_iterator<char>(file)), istreambuf_iterator<char>());// 读取文件内容
        file.close(); // 关闭文件
        return content; // 返回文件内容
    }
    return string(); // 返回空值，可写为 return {};
}

void test_optional() {
    // 旧版本文件读取测试：
    bool open_success = false;
    string content = read_file_as_string("test_file.txt", open_success);
    if (open_success)  // 也可以写为 if (content.empty()) 或者 if (content == "")
        cout << "文件内容如下：\n" << content << endl;
    else
        cout << "文件打开失败！" << endl;

    // 新版本文件读取测试，返回 optional 类型变量：
    auto content_optional = read_file_as_optional("test_file.txt");
    /*if (content_optional.has_value())  // 判断 optional 变量是否包含值，可直接写为 if (content_optional)
        cout << "文件内容如下：\n" << content_optional.value() << endl; // value() 函数获取值
    else
        cout << "文件打开失败！" << endl; */
    auto content_str = content_optional.value_or("文件未读取");
    // value_or 获取 optional 变量的值，如果为空则返回传入的任何值（多种类型的），这里返回 "文件未读取"
    cout << "文件读取如下：\n" << content_str << endl;
}




enum class ErrorCode {  // 枚举类型定义，用于定义错误代码，成员默认为私有
    None, NotFound, Empty, Invalid
};

static variant<string, ErrorCode> read_file(const string& filename) { // 函数可以返回多种类型
    fstream file(filename); // 打开文件
    if (!file.is_open()) // 判断文件是否打开成功
        return ErrorCode::NotFound; // 返回错误代码
    string content;
    getline(file, content); // 读取文件一行内容，不包括换行符
    if (content.empty()) // 判断文件是否为空
        return ErrorCode::Empty; // 返回空文件代码
    file.close(); // 关闭文件
    return content; // 返回文件内容
}

void test_more_types()
{
    variant<int, double, string, ErrorCode> var;
    // 声明一个变体类型，可以存储不同类型的数据（整数、浮点数、字符串、错误代码类类型）
    var = "variant test string";
    cout << "sizeof(var) = " << sizeof(var) << "\t" // 输出变体类型占用内存大小
        << "variant test string: " << get<string>(var) << ", var.index() = " << var.index() << endl;
    // std::get<>() 函数用于获取变体类型中存储的字符串数据，index() 函数用于获取变体类型中存储数据的下标（类型）
    var = 123;
    cout << "variant test int: " << get<int>(var) << ", var.index() = " << var.index() << endl;
    var = 3.14;
    if (auto ptr1 = get_if<double>(&var)) // get_if() 接收和返回都是指针
        // 使用 get_if() 函数判断获取变体类型中存储的浮点数数据，并使用 auto 关键字声明指针类型
        cout << "variant test double: " << *ptr1 << ", var.index() = " << var.index() << endl;
    cout << "--------------------------------------------------------\n\n";
    auto file_content = read_file("test_file.txt"); // 调用 read_file() 函数读取文件内容
    if (auto ptr2 = get_if<string>(&file_content))
        // 使用 get_if() 函数判断获取变体类型中存储的字符串数据，并使用 auto 关键字声明指针类型
        cout << "variant test string: " << *ptr2
        << ", file_content.index() = " << file_content.index() << endl;
    else if (auto ptr3 = get_if<ErrorCode>(&file_content))
        // 使用 get_if() 函数判断获取变体类型中存储的错误代码数据，并使用 auto 关键字声明指针类型
        cout << "variant test ErrorCode: " << static_cast<int>(*ptr3)
        << ", file_content.index() = " << file_content.index() << endl;
    else
        cout << "variant test unknown type: " << endl;
    // 输出变体类型中存储的不同类型数据，并判断存储的数据类型
}


//static uint32_t s_alloc_count; // 静态变量，记录分配的内存块数量 uint32_t == unsigned int
void* operator new(size_t size) { // new 运算符重载
    if (size == 0)
        return nullptr;
    //++s_alloc_count;
    //cout << "operator new called, size = " << size << endl;
    return malloc(size); // 调用 malloc() 函数分配内存，重载该操作符是为了查看调试时调用堆栈内存分配的情况
}

//void operator delete(void* ptr) noexcept { // delete 运算符重载
//    free(ptr); // 调用 free() 函数释放内存
//}

struct BigClass { // 自定义类
    string name;
    string address;
    string phone;
    string city;
    string homepage;
};

void test_any_type() {
    any ay1; // 声明一个 any 类型变量，可以存储不同类型的数据
    ay1 = 123; // 存储整数类型数据
    cout << "any test int: " << any_cast<int>(ay1) << endl;
    ay1 = string("any test string"); // 存储字符串类型数据
    cout << "any test string: " << any_cast<string>(ay1) << endl;
    // 调试可以看到，any_cast<string>() 函数调用了 string 构造函数，因此会有内存分配和释放的操作
    // 这里的 any_cast 只调用了 basic_string 没有调用 any 类的
//string& str = any_cast<string&>(ay1);// 获取字符串类型数据的引用，需要用引用类型声明，对于函数确保使用模板
    ay1 = BigClass(); // 调试可以看到调用了 any 类里面的 = 生成，此前调用的 _Emplace 使用了 new 方式
    // _Emplace 函数包含 _Storage._BigStorage._Ptr 即说明使用了大类型数据存储的方式
}
